/*
	system_config_tables.h

	contains function headers for setting up GDT and IDT

	Author: Aidan Goddard 30/4/13
*/

#ifndef TABLES_H_INCLUDED
#define TABLES_H_INCLUDED

#include "types.h"

// GDT, IDT stuff
void SetupGDT();
void SetupIDT();

// DO NOT MODIFY THESE TABLES - ASM ROUTINES RELY ON THINGS BEING IN THE CORRECT PLACE

// system tables
// random stuff table
typedef struct TBL_SYSCONFIG_STUFF TBL_SYSCONFIG_STUFF;
struct __attribute__((__packed__)) TBL_SYSCONFIG_STUFF
{
	uint32_t APIC_ticks_sec;
	uint32_t PIC_spurious_7_count;
	uint32_t PIC_spurious_15_count;
	uint32_t APIC_spurious_count;
	uint64_t KLIB_ENTRY;
	uint64_t time; 			// system time in ms since jan 1 1900 UTC
	uint64_t start_time;	// time the system was booted in ms since jan 1 1900 UTC
	uint32_t build_date;
	uint32_t build_number;
	uint32_t reserved[52];
};

// ISA -> GSI mapping table
typedef struct TBL_SYSCONFIG_ISA_GSI TBL_SYSCONFIG_ISA_GSI;
struct __attribute__((__packed__)) TBL_SYSCONFIG_ISA_GSI
{
	uint32_t GSI;
	uint32_t trigger_mode;	// 1 = edge, 0 = level
	uint32_t polarity;	// 1 = active high, 0 = active low
	uint32_t reserved;
};

// GSI mapping table
typedef struct TBL_SYSCONFIG_GSI TBL_SYSCONFIG_GSI;
struct __attribute__((__packed__)) TBL_SYSCONFIG_GSI
{
	uint32_t IOAPIC_ID;		// 0xffffffff for no IOAPIC
	uint32_t IOAPIC_input_number;
	uint32_t type;			// 0 = unused, 1 = ISA, 2 = PCI, 3 = NMI
	uint32_t ISA_IRQ;		// if type == 1
	uint32_t trigger_mode;
	uint32_t polarity;
	uint32_t PCI_INT;		// if type == 2, 0 = unknown, 1 = A, 2 = B, etc
	uint32_t reserved[9];
};

// IOAPIC info table
typedef struct TBL_SYSCONFIG_IOAPIC TBL_SYSCONFIG_IOAPIC;
struct __attribute__((__packed__)) TBL_SYSCONFIG_IOAPIC
{
	uint32_t IOAPIC_ID;		// 0xffffffff for no IOAPIC
	uint32_t IOAPIC_address;
	uint32_t GSI_base;
	uint32_t input_count;
};

// CPU info table
typedef struct TBL_SYSCONFIG_CPU TBL_SYSCONFIG_CPU;
struct __attribute__((__packed__)) TBL_SYSCONFIG_CPU
{
	uint32_t APIC_ID;
	uint32_t ACPI_CPU_ID;
	uint32_t enabled;	// 0 = disabled, 1 = enabled, 2 = startup failed
	uint32_t TSS_descriptor;
	uint32_t LINT0_type; 	// 0 = unused, 1 = NMI, 2 = exint
	uint32_t LINT1_type;
	uint32_t LINT0_polarity;
	uint32_t LINT0_triggermode;
	uint32_t LINT1_polarity;
	uint32_t LINT1_triggermode;
	uint32_t reserved[6];
};

// GSI 'reservation' table
// index into table is the 0-based GSI

// note that where the IRQ line is shared by devices, the line will be 'owned' by the system
typedef struct TBL_SYSCONFIG_GSI_RESERVATION TBL_SYSCONFIG_GSI_RESERVATION;
struct __attribute__((__packed__,aligned(32))) TBL_SYSCONFIG_GSI_RESERVATION
{
	uint32_t	is_reserved; // 0 = available, 1 = reserved
	uint32_t	owner_id; // -1 for system
	uint64_t	key; // reservation key
};

// ISR reservation table
typedef struct TBL_SYSCONFIG_ISR_RESERVATION TBL_SYSCONFIG_ISR_RESERVATION;
struct __attribute__((__packed__,aligned(32))) TBL_SYSCONFIG_ISR_RESERVATION
{
	uint32_t	is_reserved; // 0 = available, 1 = reserved
	uint32_t	owner_id; // -1 for system
	uint64_t	key; // reservation key
};


// base table
typedef struct TBL_SYSCONFIG TBL_SYSCONFIG;
struct __attribute__((__packed__)) TBL_SYSCONFIG
{
	TBL_SYSCONFIG_STUFF 			tbl_stuff;
	TBL_SYSCONFIG_ISA_GSI 			tbl_isa_gsi[16];
	TBL_SYSCONFIG_GSI 				tbl_gsi[256];
	TBL_SYSCONFIG_IOAPIC 			tbl_ioapic[16];
	TBL_SYSCONFIG_CPU 				tbl_cpu[32];
	TBL_SYSCONFIG_GSI_RESERVATION	tbl_gsi_reservations[256];
	TBL_SYSCONFIG_ISR_RESERVATION	tbl_isr_reservations[256];
};


// system table access functions
TBL_SYSCONFIG *GetSystemConfigBase();
void SetAPICTimerBusSpeed(uint32_t ticks_per_second);
uint32_t GetAPICTimerBusSpeed();
uint32_t SystemTableLock();
void SystemTableUnlock(int CPU);

#endif
